#ifndef _UTIL_FONT_H_
#define _UTIL_FONT_H_

#include <map>
#include <string>
#include <vector>
#include "graphics/color.h"
#include "num/named_set.h"
#include "math/vec2.h"
#include "math/vec4.h"

/** 
 * Font:
 * \brief Font Object
 */
class Font
{
public:
	enum	FONT_FLAGS
	{
		FONT_TOP               = 0x01 << 0,
		FONT_LEFT              = 0x01 << 1,
		FONT_CENTER            = 0x01 << 2,
		FONT_RIGHT             = 0x01 << 3,
		FONT_VCENTER           = 0x01 << 4,
		FONT_BOTTOM            = 0x01 << 5,
		FONT_WORDBREAK         = 0x01 << 6,
		FONT_SINGLELINE        = 0x01 << 7,
		FONT_BOLD			   = 0x01 << 8,
		FONT_FILTERED		   = 0x01 << 9,
		FONT_EXPANDTABS       = 0x01 << 10,
		FONT_TABSTOP           = 0x01 << 11,
		FONT_NOCLIP            = 0x01 << 12,
	};

	// control characters
	static const	int		MAX_CHAR = 1024;
	static const	int		MAX_LINES = 100;
	static const	int		TAB_WIDTH = 30;

	static const unsigned short		FORCE_LB =  L'\n';
	static const unsigned short		FORCE_TAB = L'\t';
//	static const unsigned short		FORCE_WS = L'$';  // deprecated flag
	static const unsigned short		FORCE_BOLD =  0x00a3;// L'£'; 
	static const unsigned short		FORCE_NBSP = 0x00B7; // middle dot as non-breaking space

	static	bool					IsEscapeChar(unsigned short ID);

    /**
     * Constructor
     */
                    Font( const std::string& Name );
    /**
     * delete all buffers
     *  
     */
	virtual			~Font();

	void			SetUnderline(bool b) { m_AddLine = b; };
    /**
     * Initialize the font
     * @param _Face      name of Font Face to create default font from
     * @param _Height    height (in pixels) of font
     * @param _Width     width (in pixels) of font
     * @param _Italic    Italic?
     */
    virtual bool	Init(	 const std::string& _Face,
                             unsigned long      _Width,
                             unsigned long      _Height,
							 bool				_Italic = false,
							 unsigned int		_Weight = 900);

	virtual void	Resize(const std::string& _Face, int Width, int Height, int Weight, unsigned long CharSet);
	virtual void	Render(	const std::string& Text,
							const math::Vec2& Pos,
							const math::Vec2& Size = math::Vec2(1.0f, 1.0f),
							unsigned int Flags = FONT_WORDBREAK,
							COLOR		Color = ColorRGBA(255, 255, 255),
							bool	Clip = false);

	virtual void	Render(	const std::wstring& Text,
							const math::Vec2& Pos,
							const math::Vec2& Size = math::Vec2(1.0f, 1.0f),
							unsigned int Flags = FONT_WORDBREAK, 
							COLOR		Color = ColorRGBA(255, 255, 255),
							bool	Clip = false) = 0;


	virtual void	RenderCentered(	const std::string& Text,
							const math::Vec2& Pos,
							const math::Vec2& Size = math::Vec2(1.0f, 1.0f),
							unsigned int Flags = FONT_WORDBREAK,
							COLOR		Color = ColorRGBA(255, 255, 255),
							bool	Clip = false);

	virtual void	RenderCentered(	const std::wstring& Text,
							const math::Vec2& Pos,
							const math::Vec2& Size = math::Vec2(1.0f, 1.0f),
							unsigned int Flags = FONT_WORDBREAK, 
							COLOR		Color = ColorRGBA(255, 255, 255),
							bool	Clip = false) ;


	virtual void	GetTextExtent(	const std::string& Text,
									const math::Vec2& Box,
									math::Vec2& From,
									math::Vec2& Size,
									unsigned int Flags = FONT_WORDBREAK,
									int* pLineC = NULL);

	virtual void	GetTextExtent(	const std::wstring& Text,
									const math::Vec2& Box,
									math::Vec2& From,
									math::Vec2& Size,
  									unsigned int Flags = FONT_WORDBREAK,
									int* pLineC = NULL);

	virtual bool	GetCharOffsets( unsigned short ch,
									int* pOffsetX,
									int* pPreOffset );
							
	virtual float	GetHeight();
	int				GetLineSpacing() const { return m_LineSpacing; };
	void			SetLineSpacing(int v) { m_LineSpacing = v; };

	const std::string&	GetName() const { return m_Name; };

	virtual void			Flush();
	virtual void			FlushSprite() {};
	virtual void			Recreate();

	void					SetBorder(bool b) { m_AddBorder = b; };
	bool					GetBorder() const { return m_AddBorder; };

	void					SetColorMask(const math::Vec4& color)				{ m_ColorMask = color; }
	void					SetColorMask(float r, float g, float b, float a)	{ SetColorMask(math::Vec4(r,g,b,a)); }


	struct					GlyphData
	{
		unsigned short		Glyph;
		bool				ToCache;
		float				TimeStamp;	// last used

		// info about the pos and size on the bitmap
		int					xp, yp;
		int					Width, Height;
		int					OffsetX, PreOffset;
		
		// info about the pos and size on the texture (in tex-coords)
		int					TexX, TexY, TexW, TexH;	// position in texture space
		math::Vec2			Pos, Size;				// derived from texture space for speed 
	};
	struct					LineData
	{
		void				Reset()
		{
			From = To = 0;
			Width = Height = 0.0f;
		}
		int					From, To;				// indices into the glyph
		float				Width, Height;			// width and height for entire line
		float				x, y;					// start-x and start-y from last time it was rendered
	};

	virtual void			RenderGlyphData(const math::Vec2& Pos, const math::Vec2& Size, COLOR Color, LineData* LineA, GlyphData**	GlyphA, int Lines, int Glyphs, unsigned int Flags, bool Draw);
	void					BuildGlyphData(const std::wstring& Text, int	Width, int Height, LineData* LineA, GlyphData**	GlyphA, int& Lines, int& Glyphs, bool Draw);
	inline void				RecalcLineWidth(const std::wstring& Text, GlyphData** GlyphA, LineData* pLine);

protected:
	virtual bool			CustomInit() {return true;};
	virtual void			CacheGlyphs(bool	CopyRect) {};
	virtual GlyphData*		GetGlyphIndex(unsigned short Glyph);
	virtual void			SetTexture() = 0;

	ADD_OVERRUN(m_StartGuard);
	num::NamedSet<GlyphData*>	m_GlyphMap;

	math::Vec2				m_MinExtent, m_MaxExtent;
	int						m_TexWidth, m_TexHeight;
	COLOR				m_Highlight;
	math::Vec4				m_ColorMask;

	// info
	std::string			m_Name;
	std::string			m_Face;
	unsigned int		m_Width, m_Height;
	unsigned int		m_Weight;
	int					m_LineSpacing;
	bool				m_Italic;
	bool				m_AddBorder;
	bool				m_AddLine;
	ADD_OVERRUN(m_EndGuard);

};

#endif // _UTIL_FONT_H_